package main

import (
	"container/list"
	"fmt"
	"log"

	"github.com/gotk3/gotk3/gtk"
)

var labelList = list.New()

func Addremove() {
	gtk.Init(nil)

	win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
	if err != nil {
		log.Fatal("无法创建窗口：", err)
	}
	win.SetTitle("添加/删除小部件示例")
	win.Connect("摧毁", func() {
		gtk.MainQuit()
	})

	win.Add(windowWidget())
	win.ShowAll()

	gtk.Main()
}

func windowWidget() *gtk.Widget {
	grid, err := gtk.GridNew()
	if err != nil {
		log.Fatal("无法创建网格：", err)
	}
	grid.SetOrientation(gtk.ORIENTATION_VERTICAL)
	// Just as a demonstration, we create and destroy a Label without ever adding it to a container.  In native GTK, this would result in a memory leak, since gtk_widget_destroy() will not deallocate any memory when passed a GtkWidget with a floating reference.
	// gotk3 handles this situation by always sinking floating references of any struct type embedding a glib.InitiallyUnowned, and by setting a finalizer to unreference the object when Go has lost scope of the variable.  Due to this design, widgets may be allocated freely without worrying about handling memory incorrectly.
	// The following code is not entirely useful (except to demonstrate this point), but it is also not "incorrect" as the C equivalent would be.

	//作为一个演示，我们创建并销毁一个标签，而从不将其添加到容器中。在本机GTK中，这将导致内存泄漏，因为GTK_widget_destroy（）在传递带有浮动引用的GtkWidget时不会释放任何内存。 gotk3通过始终下沉嵌入glib的任何结构类型的浮动引用来处理这种情况。初始无主，并通过设置终结器在Go失去变量范围时取消引用对象。由于这种设计，小部件可以自由分配，而不必担心错误地处理内存。下面的代码并不完全有用（除了说明这一点），但它也不像C等价物那样“incorrect不正确”。
	unused, err := gtk.LabelNew("这个标签从未使用过")
	if err != nil {
		// Calling Destroy() is also unnecessary in this case.  The memory will still be freed with or without calling it.
		// 在这种情况下，调用Destroy()也是不必要的。无论是否调用，内存仍将被释放。
		unused.Destroy()
	}

	sw, err := gtk.ScrolledWindowNew(nil, nil)
	if err != nil {
		log.Fatal("无法创建滚动窗口：", err)
	}

	grid.Attach(sw, 0, 0, 2, 1)
	sw.SetHExpand(true)
	sw.SetVExpand(true)

	labelsGrid, err := gtk.GridNew()
	if err != nil {
		log.Fatal("无法创建网格：", err)
	}
	labelsGrid.SetOrientation(gtk.ORIENTATION_VERTICAL)

	sw.Add(labelsGrid)
	labelsGrid.SetHExpand(true)

	insertBtn, err := gtk.ButtonNewWithLabel("添加标签")
	if err != nil {
		log.Fatal("无法创建按钮：", err)
	}
	removeBtn, err := gtk.ButtonNewWithLabel("去掉标签")
	if err != nil {
		log.Fatal("无法创建按钮：", err)
	}

	nLabels := 1
	insertBtn.Connect("clicked", func() {
		var s string
		if nLabels == 1 {
			s = fmt.Sprintf("插入 %d 标签.", nLabels)
		} else {
			s = fmt.Sprintf("插入 %d 标签.", nLabels)
		}
		label, err := gtk.LabelNew(s)
		if err != nil {
			log.Print("无法创建标签:", err)
			return
		}

		labelList.PushBack(label)
		labelsGrid.Add(label)
		label.SetHExpand(true)
		labelsGrid.ShowAll()

		nLabels++
	})

	removeBtn.Connect("clicked", func() {
		e := labelList.Front()
		if e == nil {
			log.Print("没有要删除的内容")
			return
		}
		lab, ok := labelList.Remove(e).(*gtk.Label)
		if !ok {
			log.Print("要删除的元素不是*gtk.Label")
			return
		}
		// (*Widget).Destroy() breaks this label's reference with all
		// other objects (in this case, the Grid container it was added
		// to).
		lab.Destroy()

		// At this point, only Go retains a reference to the GtkLabel.
		// When the lab variable goes out of scope when this function
		// returns, at the next garbage collector run, a finalizer will
		// be run to perform the final unreference and free the widget.
	})

	grid.Attach(insertBtn, 0, 1, 1, 1)
	grid.Attach(removeBtn, 1, 1, 1, 1)

	return &grid.Container.Widget
}
